Skip to content

Specify and document current PM_DEVICE behavior, including PM_DEVICE=n and device_deinit() #90275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

bjarki-andreasen
Copy link
Contributor

@bjarki-andreasen bjarki-andreasen commented May 21, 2025

This PR aims to document the status quo of device power management to provide a foundation for current driver development, and future refactoring discussions, since we need to agree on the current state before being able to discuss the future state :)

The PR also adds the missing counterpart to pm_device_driver_init().

Copy link
Contributor

@JordanYates JordanYates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this function? It seems odd that it is running functions when CONFIG_PM_DEVICE=n but doesn't do anything when CONFIG_PM_DEVICE=y?

@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented May 21, 2025

What is the purpose of this function? It seems odd that it is running functions when CONFIG_PM_DEVICE=n but doesn't do anything when CONFIG_PM_DEVICE=y?

Check out subsys/pm/device.c for now it simply ensures the device is not in use (suspended or off) to prevent deinit of a device which is in use. Even if it did nothing if CONFIG_PM_DEVICE=n, that would still be fine IMO, its there to allow device_deinit() to undo what device_init() did through pm_device_driver_init()

Copy link
Contributor

@JordanYates JordanYates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, this is a simple check ensuring the device is not in use

What is stopping a final implementation from being implemented now? The function should have defined semantics, and they should be implemented properly when the function is introduced, not modified at some point in "the future".

@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented May 22, 2025

For now, this is a simple check ensuring the device is not in use

What is stopping a final implementation from being implemented now? The function should have defined semantics, and they should be implemented properly when the function is introduced, not modified at some point in "the future".

This is all we need for now, I don't think there is a "final" implementation, its just a hook for doing whatever is required of PM at a given time :)

return rc;
}

rc = action_cb(dev, PM_DEVICE_ACTION_TURN_OFF);
Copy link
Contributor

@JordanYates JordanYates May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right, the device is not literally being turned off, just the software construct destroyed.
This would lead to GPIO's being put into incorrect states if used generically, which the PM API is.

Overloading the meaning of PM_DEVICE_ACTION_TURN_OFF is a bad idea IMO.

Copy link
Contributor Author

@bjarki-andreasen bjarki-andreasen May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with removing the call to TURN_OFF, given that all resources like GPIOs are released as part of device_deinit(), I think you are right that it makes little sense to act as if the driver is being turned off before being deinitialized.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree about it

@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from 4ea0b00 to 0f5a01c Compare May 22, 2025 12:20
@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from 0f5a01c to 4a6a1d6 Compare May 25, 2025 18:55
ceolin
ceolin previously approved these changes May 26, 2025
@bjarki-andreasen
Copy link
Contributor Author

@JordanYates could you revisit this one?

Copy link
Contributor

@JordanYates JordanYates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still not clear to me how this helps to reliably implement the requirements of the device_deinit API.

* When a device is de-initialized, it will release any resources it has
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
* be left as in its reset state.
*
* @warning It is the responsibility of the caller to ensure that the device is
* ready to be de-initialized.

It's on the caller to determine whether the device can be de-initialized, not the implementation.

Why is STATE_SUSPENDED any more likely to be the "reset state" of a device than STATE_ACTIVE? In many cases the suspend state is explicitly not the reset state of a device.

@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented May 29, 2025

It's still not clear to me how this helps to reliably implement the requirements of the device_deinit API.

* When a device is de-initialized, it will release any resources it has
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
* be left as in its reset state.
*
* @warning It is the responsibility of the caller to ensure that the device is
* ready to be de-initialized.

It's on the caller to determine whether the device can be de-initialized, not the implementation.

This to my knowledge was intended to clearly indicate that there is no reference counting or other tracking of who is using the device built in to the device model (which there was with an early version of device_deinit()), not that no checks are allowed to make sure it makes sense. Otherwise surely

zephyr/kernel/device.c

Lines 150 to 152 in 600cae6

if (!dev->state->initialized) {
return -EPERM;
}
would not exist :) The function returns a value, it can fail, we are allowed to do additional sanity checking.

Why is STATE_SUSPENDED any more likely to be the "reset state" of a device than STATE_ACTIVE? In many cases the suspend state is explicitly not the reset state of a device.

If CONFIG_PM_DEVICE=n, state is not checked, instead it just calls the suspend action. If CONFIG_PM_DEVICE=y, then device has to be suspended, thus STATE_SUSPENDED or STATE_OFF are explicitly states from which the "reset state" can be safely entered. The only difference between STATE_SUSPENDED and STATE_OFF would be whether the hardware block lost power, and thus was implicitly reset.

@JordanYates
Copy link
Contributor

As a concrete request, please document what the function is actually supposed to be doing beyond just @brief Deinit a device driver. It is easier to check that an intended behavior makes sense and that an implementation matches the intended behavior than to try and reason about how a particular implementation is supposed to fit into the larger device_deinit API based only on code.

decsny
decsny previously approved these changes Jun 27, 2025
ceolin
ceolin previously approved these changes Jun 27, 2025
*
* The initial power state expected by the system is:
*
* - ACTIVE if CONFIG_PM_DEVICE=n or (CONFIG_PM_DEVICE=y and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very cryptic and very difficult to understand, simplify this in words instead of pseudo conditional code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly expect using pseudo code to describe conditional logic is the opposite of "confusing and very difficult to understand" in a project tailored to software engineers...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

software engineers can look at the code and figure out the details of the logic, this is a docstring that should explain an API, not repeat the logic in the code. If that was an easy condition, sure, but when you have a condition with 3 or 4 parts involving negations and a mix of AND/OR it becomes less usefull in a docstring.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

software engineers can look at the code and figure out the details of the logic

This section is part of the @details portion of the docstring. It describes only what state the driver will be in after the function is called, not how to get to that state, which would be the internal logic. Describing what the target state of something is, AFTER the function has performed some action on a resource, is definitely something that should be part of the docstring.

NULL
);

Device Model without Power Management Support
Copy link
Member

@nashif nashif Jun 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This title is confusing and IMO wrong, i.e. it would not be here in the first places if it was "without Power Management". This mode is using "device driver PM action hook", so it does use power management implementation of the driver.

Maybe: "Device model driven Power Management" ?

Copy link
Contributor Author

@bjarki-andreasen bjarki-andreasen Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Device model driven" is not a phrase used anywhere in the project. Users would have no way of understanding what this section describes without reading the section first if we change to this title I believe.

Breaking the current title down, it has a good likelihood of being understood as the intended "device driver model with PM_DEVICE=n"

"Device Model", as in device driver model, "without Power Management", as in PM_DEVICE=n

Copy link
Contributor Author

@bjarki-andreasen bjarki-andreasen Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment regarding the same thing #90275 (comment) and the definition of the PM_DEVICE config:

zephyr/subsys/pm/Kconfig

Lines 78 to 86 in ad4c3e3

config PM_DEVICE
bool "Device Power Management"
help
This option enables the device power management interface. The
interface implemented by device drivers are called by the power
management subsystem. This allows device drivers to do any
necessary power management operations like turning off
device clocks and peripherals. Device drivers may also save
and restore states in these hook functions.

We can change it to "Device Model without Device Power Management"? That seems to fit the config and is clearer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to "Device Model without Device Power Management"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PM_DEVICE kconfig help "This option enables the device power management interface. .."

I wonder what this interface is exactly and if anything would actually work without this interface being enabled or used. Isnt

static inline int pm_device_driver_deinit(const struct device *dev, pm_device_action_cb_t action_cb)
{
        return action_cb(dev, PM_DEVICE_ACTION_SUSPEND);
}

calling this interface when CONFIG_PM_DEVICE=n , i.e.:

  • PM_DEVICE_ACTION_SUSPEND is part of this interface
  • pm_device_action_cb_t is also part of this interface
  • The implementation of this interface is guarded in most device drivers with #ifdef CONFIG_PM_DEVICE, which confirms the above.
  • pm_device_driver_deinit itself is part of this interface

So you are using device power management in a different way. "without Device Power Management" is simply not true.

This is the main issue here and why every reviewer was "confused" and many of the comments in this PR are talking about confusion.

Copy link
Contributor Author

@bjarki-andreasen bjarki-andreasen Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We spent two second arch meetings discussing this semantic issue. I do not find it efficient nor reasonable to continue to block this PR to repeat that same discussion.

The title "Device Model without Device Power Management" follows the same wording as the existing title

Device Model with Power Management Support
which describes PM_DEVICE=y, while describing the case where PM_DEVICE=n. Thus, "with" is changed to "without".

Adding "Device" in there was an improvement IMO, but it can be reverted again no problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We spent two second arch meetings discussing this semantic issue. I do not find it efficient nor reasonable to continue to block this PR to repeat that same discussion.

We do not review PRs in meetings and we need to continue discussing this.
The general agreement was that the implementation is "fine" for now, knowing there are issues we need to resolve to avoid confusion and fix / improve existing drivers to follow a model that works for them.

I disagree this is just a semantic issue. Even if it was, the documentation needs to reflect reality.

Take another look at #90275 (comment) please and address that comment.

The title "Device Model without Device Power Management" follows the same wording as the existing title

Device Model with Power Management Support

which describes PM_DEVICE=y, while describing the case where PM_DEVICE=n. Thus, "with" is changed to "without".
Adding "Device" in there was an improvement IMO, but it can be reverted again no problem.

Given that we heavily rely on device power management interface, even with PM_DEVICE=n, how about changing the title to " ... with Partial Device Power Management"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that, argument is solid, updated to "Device Model with Partial Device Power Management Support"


return 0;
}
struct dummy_driver_data {
Copy link
Member

@nashif nashif Jun 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a lot of code that sooner or later will become stale , how about updating samples/subsys/pm/device_pm/, make it an annonated sample and instead reference the code from that sample here instead? This way we will know the code works and compiles and we have things in one place only.

Copy link
Contributor Author

@bjarki-andreasen bjarki-andreasen Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example code will be updated whenever something changes in PM, that I will ensure, just like anything else in the docs will be updated to not become stale...

Such a sample would be very complex, given we have to emulate the most complex possible driver, mock PM states, mock GPIOs, mock busses, it would be quite the undertaking, and very much outside the scope of this PR. Not saying its a bad thing, I think it would be nice to have a single test suite with a mock driver covering all of device PM with its different states, but yeah, scope :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the sample in samples/subsys/pm/device_pm/src/dummy_driver.c already does most of that.

This example code will be updated whenever something changes in PM, that I will ensure, just like anything else in the docs will be updated to not become stale...

Not doubting your willingness to that, but this is an area that can become stale very fast if the code is not compiled. Putting the code in a sample and referencing it here through inlining will get you the same results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, from previous comment: "Not saying its a bad thing, I think it would be nice to have a single test suite with a mock driver covering all of device PM with its different states, but yeah, scope :)"

Copy link
Contributor

@teburd teburd Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had this issue in other areas, I'd like to have compiled inline samples in the docs more or less, but the only way to do this today is make it a full fledged sample with independent docs and all of that... which makes no sense given its meant to be inline in the context of the docs.

I asked before about this before but we didn't come to any agreement on how best to do this.

Ideal scenario in my mind:

  • inline doc samples go into a dedicated samples/doc_inline directory or something like it
  • this directory contains samples meant to be inlined into docs and can therefore skip being documented, they are contextual samples going into a larger doc page.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If inlining is a an issue, we need to figure out something. @kartben how does this work in general and how we can improve this?
In the context of this PR, this can be done later. It is just lot of code being added to the docs which runs the risk of becoming stale, we have seen this in other areas in the past.

*
* @note
* Device context may be lost.
* @details The device should be put into its lowest internal power state,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think the details about transitions here do not belong into the state definition, but fine, we will see how this will work out and can always change it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We most likely will if we move these states to the device model for example :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we need to rethink this as a whole and consider this option.

a :c:enum:`pm_device_state`.
Each :c:enum:`pm_device_state` state is defined as follows:

- ``OFF``: Device hardware is not powered. This is the initial state from which
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my point, this is a state, you define it as a state, how you got there involves a lot of logic and conditions that should not be part of the definition of what the state is. All of that can be left to the PM mode you are using.

Same comment applies to all states below.

But ok, lets see how this goes....

@bjarki-andreasen bjarki-andreasen dismissed stale reviews from ceolin and decsny via d6b30b7 June 30, 2025 09:35
@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from fd16cb4 to d6b30b7 Compare June 30, 2025 09:35
@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented Jun 30, 2025

Update

Updated the titles

  • "Device Model with Power Management Support"
  • "Device Model without Power Management Support"

which primarily focus on the config CONFIG_PM_DEVICE=y or n, to specify "Device Power Management Support" so they now read

  • "Device Model with Device Power Management Support"
  • "Device Model without Device Power Management Support"

@carlescufi carlescufi requested review from ceolin and decsny June 30, 2025 11:41
@carlescufi
Copy link
Member

@nashif @decsny @ceolin PTAL at the last push

ceolin
ceolin previously approved these changes Jul 1, 2025
- Specify "Device" Power Management Support in sections covering
  CONFIG_PM_DEVICE=y or n
- Extend the enum pm_device_state docstrings to define and detail
  expectations of devices in each enum pm_device_state state.
- Extend pm device driver code example with more concise comments
  and include pm_device_driver_init, pm_device_driver_deinit, and
  DEVICE_DT_INST_DEINIT_DEFINE() (device deinit feature)
- Describe the device driver PM states used if PM_DEVICE is not
  enabled.
- Note which states a device driver is initialized from and can
  be deinitialized in and why.

Signed-off-by: Bjarki Arge Andreasen <bjarki.andreasen@nordicsemi.no>
Mention introduction of pm_device_driver_deinit() in the 4.2 release
notes.

Signed-off-by: Bjarki Arge Andreasen <bjarki.andreasen@nordicsemi.no>
Copy link

sonarqubecloud bot commented Jul 1, 2025

@carlescufi carlescufi requested review from nashif, tobiwan88 and ceolin July 1, 2025 14:24
@danieldegrasse
Copy link
Contributor

@decsny can you take a look as well?

@decsny
Copy link
Member

decsny commented Jul 4, 2025

I trust that it's probably fine, I won't be able to review it properly this week, don't wait on me

@bjarki-andreasen bjarki-andreasen removed this from the v4.2.0 milestone Jul 4, 2025
@kartben kartben added this to the v4.3.0 milestone Jul 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Power Management Release Notes To be mentioned in the release notes
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.